package com.gmsk.pocket.controller;

import com.gmsk.pocket.config.BaseConfig;
import com.gmsk.pocket.entity.DocFile;
import com.gmsk.pocket.helper.HdfsFileSystem;
import com.gmsk.pocket.service.DocFileService;
import com.gmsk.pocket.service.ThreadPoolExecutorService;
import com.gmsk.pocket.utils.HashUtil;
import com.gmsk.pocket.utils.R;
import com.gmsk.pocket.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/file")
public class FileController {

    private static final Logger logger = LoggerFactory.getLogger(FileController.class);

    @Value("${fileUpload.path}")
    private String FILE_PATH;

    @Value("${hdfs.URILocation}")
    private String HDFS_URI;

    @Value("${fileUpload.tmpDir}")
    private String TMPDIR;

    @Autowired
    BaseConfig baseConfig;

    @Autowired
    private DocFileService docFileService;

    @Autowired
    private ThreadPoolExecutorService executorService;
    @RequestMapping(value = "/mulp-upload", method = RequestMethod.POST)
    @ResponseBody
    public R HDFSMulpUpload(HttpServletRequest request) {
        List<MultipartFile> files = ((MultipartHttpServletRequest)request).getFiles("file");
        try {
        for (MultipartFile file: files) {
                String fileName = null;
                if (file.isEmpty()) {
                    logger.error("file name is NULL !");
                    R.error(400, "file not found");
                }
                fileName = file.getOriginalFilename();
                String path = TMPDIR + fileName;
                File dest = new File(path);
                if (!dest.getParentFile().exists()) {
                    dest.getParentFile().mkdirs();
                }
                file.transferTo(dest);
                HdfsFileSystem.copyFileToHDFSByFileObj(dest, HDFS_URI + "/" + fileName);
                dest.delete();
                logger.info("{} uploaded to HDFS successfully", fileName);
                return  R.ok();
        }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return R.error(400, "error");
    }


    /**
     * 上传文件，并保存到ES，用于检索，如果是word等文件，则进行pdf转化和正文抽取
     * @param file
     * @return
     */
    @RequestMapping(value = "upload")
    public R HDFSupload(@RequestParam("file")MultipartFile file) {
        String fileName = null;
        try {
            if (file.isEmpty()) {
                logger.error("file name is NULL !");
                R.error(400, "file not found");
            }
            String uid =  UUID.randomUUID().toString().replace("-", "");
            String suffix = StringUtils.getFileSuffix(file.getOriginalFilename());
            fileName = file.getOriginalFilename();
            String path = TMPDIR + uid +  "." + suffix;
            File dest = new File(path);
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
            file.transferTo(dest);
            HdfsFileSystem.copyFileToHDFSByFileObj(dest, HDFS_URI + "/"  +  uid +  "." + suffix);
            logger.info("{} uploaded to HDFS successfully", fileName);
            DocFile docFile = new DocFile();
            docFile.setFileName(uid +  "." + suffix);
            docFile.setOriginalFileName(fileName);
            docFile.setFileSize((int) file.getSize());
            docFile.setFileIndex(0);
            docFile.setFileConvert(0);
            docFile.setFileOriginalType(file.getContentType());
            docFile.setFileSha256(HashUtil.sha256(dest));
            docFile.setFileType(suffix);
            docFileService.insert(docFile);
            executorService.singleExecute(() -> docFileService.transFile(docFile));
            return  R.ok().put("data", docFile.getId());
        }catch (Exception e) {
            e.printStackTrace();
        }
        return R.error(400, "error");
    }

    @RequestMapping(value = "download", method = RequestMethod.GET)
    public R downloadHDFSFile(HttpServletRequest request, HttpServletResponse response) {
        Integer fileId = Integer.valueOf(request.getParameter("id"));
        if (null == fileId) {
            logger.error("file name is null !");
            return R.error(400, "file is null");
        }
        DocFile docFile = docFileService.select(fileId);
        if (!HdfsFileSystem.exists(HDFS_URI,docFile.getFileName())) {
            logger.error("{}/{} not exist in HDFS", HDFS_URI, docFile.getFileName());
            return R.ok();
        }
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Expires", "0");
        response.setHeader("charset", "utf-8");
        response.setContentType("application/force-download");//force not to open downloaded file
        response.setHeader("Content-Transfer-Encoding", "binary");
        response.setHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(docFile.getOriginalFileName()) + "\"");
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            HdfsFileSystem.downloadFromHDFS(HDFS_URI, docFile.getFileName(), os);
            
        } catch (IOException e) {
            logger.error("{} downloading failed. exception: {}", docFile.getFileName(), e.getMessage());
            return R.error();
        }
        return R.error();

    }

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public R list(Integer docId) {
        try{
            List<DocFile> docFiles = docFileService.selectByDocId(docId);
            return R.ok().put("data", docFiles);
        }catch (Exception e) {
            e.printStackTrace();
            return R.error();
        }
    }
}
